package de.rts.ui;

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Polygon;
import java.awt.geom.Ellipse2D;
import java.awt.image.BufferedImage;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

import javax.swing.JPanel;

import de.rts.components.RailComponent;
import de.rts.components.RailwayMap;
import de.rts.components.Segment;
import de.rts.components.Sensor;
import de.rts.components.Signal;
import de.rts.components.Train;

public class RailwayMapPanel extends JPanel
{

  /**
   * 
   */
  private static final long                   serialVersionUID = 1L;
  private static final int                    XY_PAIRS         = 4;
  private LinkedHashMap<String, Polygon>      switchSegmentList;
  private RailwayMap                          railwayMap;
  private static Map<String, Ellipse2D.Float> trainMap;
  private static Map<Sensor, Polygon>         sensorPolygonMap;
  private TimeLine                            timeLine;
  private boolean                             iceArrived       = false;
  private boolean                             cargoArrived     = false;
  private boolean                             regionalArrived  = false;

  public RailwayMapPanel(RailwayMap railwayMap)
  {
    setPreferredSize(new Dimension(1200, 500));
    this.railwayMap = railwayMap;
    this.timeLine = new TimeLine(1200, 200, BufferedImage.TYPE_INT_RGB);
    this.timeLine.drawTimeLine();
    setBackground(Color.WHITE);
    trainMap = new HashMap<String, Ellipse2D.Float>();
    sensorPolygonMap = new HashMap<Sensor, Polygon>();
    switchSegmentList = new LinkedHashMap<String, Polygon>();
    for (RailComponent component : railwayMap.getPaintList())
    {
      if (component instanceof Segment)
      {
        Segment segment = (Segment) component;
        if (segment.isSwitchSegment())
          switchSegmentList.put(segment.getSegmentId(),
            new Polygon(segment.getSwitchXCoordinates(), segment.getSwitchYCoordinates(), XY_PAIRS));
        else
        {
          List<Sensor> sensors = segment.getSensorList();
          for (Sensor sensor : sensors)
          {
            Polygon p = new Polygon(sensor.getXPositions(), sensor.getYPositions(), XY_PAIRS);
            sensorPolygonMap.put(sensor, p);
          }
        }
      }
    }
  }

  @Override
  protected void paintComponent(Graphics g)
  {
    super.paintComponent(g);
    Graphics2D g2d = (Graphics2D) g;
    g.translate(-50, 0);

    for (RailComponent component : railwayMap.getPaintList())
    {
      if (component instanceof Segment)
      {
        Segment segment = (Segment) component;
        if (segment.isSwitchSegment() && segment.isSwitchEnabled())
          createSwitchSegment(g, switchSegmentList.get(segment.getSegmentId()));
        else
        {
          createString(g, Color.BLUE, trainLabelFont, segment.getSegmentId(), segment.getLabelPosition().x,
            segment.getLabelPosition().y);
          createSegment(g, segment.getSegmentColor(), segment.getXPosition(), segment.getYPosition(),
            segment.getWidth(), segment.getHeight());
          List<Sensor> sl = segment.getSensorList();
          for (int i = 0; i < sl.size(); i++)
          {
            createSensor(g, sensorPolygonMap.get(sl.get(i)));
          }
        }
      }
      else if (component instanceof Signal)
      {
        Signal signal = (Signal) component;
        Color currentSignal = signal.getCurrentSignal();
        if (currentSignal.equals(RailComponent.RED))
          drawTrafficLight(g, currentSignal, RailComponent.WHITE, signal.getXPosition(), signal.getYPosition());
        else if (currentSignal.equals(RailComponent.GREEN))
          drawTrafficLight(g, RailComponent.WHITE, currentSignal, signal.getXPosition(), signal.getYPosition());
        else if (currentSignal.equals(RailComponent.WHITE))
          drawTrafficLight(g, RailComponent.WHITE, RailComponent.WHITE, signal.getXPosition(), signal.getYPosition());
      }
      else if (component instanceof Train)
      {
        Train train = (Train) component;
        float x = train.getPosition().x;
        float y = train.getPosition().y;
        float w = train.getSize().x;
        float h = train.getSize().y;

        if (train.getTrainId().equals("1"))
        {
          createString(g, Color.BLACK, segmentLabelFont, train.getTrainName(), train.getLabelPosition().x,
            train.getLabelPosition().y);
//          createString(g2d, Color.BLACK, segmentLabelFont, x + "/" + y, (int) x, (int) y + 20);
          createTrain(g2d, train.getTrainId(), setHSBColor(262, 13, 38), x, y, w, h);
        }
        else if (train.getTrainId().equals("2"))
        {
          createString(g, Color.BLACK, segmentLabelFont, train.getTrainName(), train.getLabelPosition().x,
            train.getLabelPosition().y);
//          createString(g2d, Color.BLACK, segmentLabelFont, x + "/" + y, (int) x, (int) y + 20);
          createTrain(g2d, train.getTrainId(), setHSBColor(180, 43, 59), x, y, w, h);
        }
        else if (train.getTrainId().equals("3"))
        {
          createString(g, Color.BLACK, segmentLabelFont, train.getTrainName(), train.getLabelPosition().x,
            train.getLabelPosition().y);
//          createString(g2d, Color.BLACK, segmentLabelFont, x + "/" + y, (int) x, (int) y + 20);
          createTrain(g2d, train.getTrainId(), setHSBColor(0, 0, 0), x, y, w, h);
        }
      }
    }
    if (iceArrived)
    {
      timeLine.setICEMarker();
      iceArrived = false;
    }

    if (cargoArrived)
    {
      timeLine.setCargoMarker();
      cargoArrived = false;
    }

    if (regionalArrived)
    {
      timeLine.setRegionalMarker();
      regionalArrived = false;
    }

    timeLine.drawTimeLine();
    g.drawImage(timeLine, 90, 400, this);
  }

  public static Ellipse2D.Float getTrainFigure(String key)
  {
    return trainMap.get(key);
  }

  public static Polygon getSensorFigure(Sensor sensor)
  {
    return sensorPolygonMap.get(sensor);
  }

  private void drawTrafficLight(Graphics g, Color top, Color bottom, int x, int y)
  {
    g.setColor(Color.BLACK);
    g.fillRoundRect(x, y, 20, 30, 30, 5);
    g.setColor(top);
    g.fillOval(x + 5, y + 2, 10, 10);
    g.setColor(bottom);
    g.fillOval(x + 5, y + 15, 10, 10);
  }

  private void createTrain(Graphics2D g2d, String trainId, Color c, float x, float y, float w, float h)
  {
    Ellipse2D.Float train = new Ellipse2D.Float(x, y, w, h);
    trainMap.put(trainId, train);
    g2d.setColor(c);
    g2d.fill(train);
  }

  private void createSegment(Graphics g, Color c, int x, int y, int width, int height)
  {
    g.setColor(c);
    g.fillRect(x, y, width, height);
  }

  private void createSensor(Graphics g, Polygon p)
  {
    g.setColor(Color.LIGHT_GRAY);
    g.fillPolygon(p);
  }

  private void createString(Graphics g, Color c, Font font, String s, int x, int y)
  {
    g.setFont(font);
    g.setColor(c);
    g.drawString(s, x, y);
  }

  private void createSwitchSegment(Graphics g, Polygon p)
  {
    g.setColor(Color.YELLOW);
    g.fillPolygon(p);
  }

  public TimeLine getTimeLine()
  {
    return timeLine;
  }

  static Color setHSBColor(int h, int s, int b)
  {
    return Color.getHSBColor((float) h / 360, (float) s / 100, (float) b / 100);
  }

  private static Font            segmentLabelFont = new Font("Serif", Font.ITALIC, 10);
  private static Font            trainLabelFont   = new Font("SansSerif", Font.BOLD, 12);

  private PropertyChangeListener listener         = new PropertyChangeListener()
                                                  {

                                                    @Override
                                                    public void propertyChange(PropertyChangeEvent e)
                                                    {
                                                      if (e.getPropertyName().endsWith("1"))
                                                        regionalArrived = (Boolean) e.getNewValue();
                                                      else if (e.getPropertyName().endsWith("2"))
                                                        cargoArrived = (Boolean) e.getNewValue();
                                                      else if (e.getPropertyName().endsWith("3"))
                                                        iceArrived = (Boolean) e.getNewValue();
                                                    }
                                                  };

  public PropertyChangeListener getListener()
  {
    return listener;
  }
}
